/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file rw_manager.c
 * @brief 读卡管理器
 */

#include "nci_feature.h"
#if IS_FEATURE_ON(NCI_FEATURE_RW)

#include "nci_rf.h"
#include "nci_module.h"
#include "nfa_discover.h"
#include "rw_utils.h"
#include "nfa_rw.h"
#include "discover_int.h"
#include "message_queue.h"
#include "rw_int.h"
#include "nci_task.h"
#include "nci_cfg.h"
#include <inttypes.h>

#define GET_RW_LOCK() \
    if (nfa_rw_request_lock() != NCI_STATUS_OK) { \
        NFCLOG_E("get rw lock failed"); \
        return NCI_STATUS_EXT_GET_LOCK_FAILED; \
    }
#define RELEASE_RW_LOCK() nfa_rw_release_lock();

#define WAIT_ACTIVATE_TIMEOUT 2000

static tMUTEX s_rw_lock = MUTEX_INIT_VAL("rw");
static tNCI_RW_TAG *s_curr_tag;
static tNCI_RW_CBACK s_cback;

/**
 * @brief 通知外部应用，标签被发现
 */
static void notify_tag_detected(tNCI_RW_TAG *p_tag) {
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (p_api && p_api->on_connect) {
        p_api->on_connect(p_tag);
    }
    tNCI_RW_CBACK p_cback = s_cback;
    if (p_cback) {
        p_cback(NCI_RW_EVT_TAG_DETECTED, (const tNCI_RW_TAG*) p_tag);
    }
}
/**
 * @brief 处理复合卡读卡事件
 */
static void on_tag_discovered(tNCI_RF_DISCOVER_PARAMS *params, uint8_t num_of_params) {
    if (nfa_rw_request_lock() != NCI_STATUS_OK) {
        NFCLOG_E("get rw lock failed");
        return;
    }
    tNCI_RF_INTF_ACTIVATED_PARAMS *p_activated_params = NULL;
    tNCI_RFST curr_state = nfa_rf_get_state();
    if (curr_state != NCI_RFST_W4_HOST_SELECT) {
        NFCLOG_E("state is not w4 host select");
        goto failed;
    }
    NFCLOG_I("on tag discovered, num_of_tag = %d", num_of_params);
    p_activated_params = osi_calloc(sizeof(tNCI_RF_INTF_ACTIVATED_PARAMS));
    if (NULL == p_activated_params) {
        NFCLOG_E("allocate memory failed");
        goto failed;
    }
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    for (size_t i = 0; i < num_of_params; ++i) {
        curr_state = nfa_rf_get_state();
        if (curr_state == NCI_RFST_POLL_ACTIVE) {
            ret = rf_deactivate(true);
            if (NCI_STATUS_OK != ret) {
                NFCLOG_E("deactivate to sleep failed, ret = %d", ret);
            }
        }
        curr_state = nfa_rf_get_state();
        if (curr_state != NCI_RFST_W4_HOST_SELECT) {
            NFCLOG_E("state is not w4 host select");
            goto failed;
        }
        tNCI_RF_DISCOVER_PARAMS *p = &params[i];
        osi_memset_s(p_activated_params, sizeof(tNCI_RF_INTF_ACTIVATED_PARAMS), 0, sizeof(tNCI_RF_INTF_ACTIVATED_PARAMS));
        ret = rf_select(p->id, p->protocol, rw_utils_get_rf_interface_from_protocol(p->protocol), WAIT_ACTIVATE_TIMEOUT, p_activated_params);
        if (NCI_STATUS_EXT_TIMEOUT == ret) {
            NFCLOG_E("select wait activate timeout");
            goto failed;
        } else if (NCI_STATUS_OK != ret) {
            NFCLOG_E("select failed, ret = %d", ret);
            goto failed;
        }
        if (NULL == s_curr_tag) {
            NFCLOG_D("intf activated, but tag info is not set");
            s_curr_tag = rw_utils_create_tag(p_activated_params);
            if (NULL == s_curr_tag) {
                NFCLOG_E("create tag failed");
                goto failed;
            }
        } else {
            ret = rw_utils_add_tech(s_curr_tag, p_activated_params);
            if (ret != NCI_STATUS_OK) {
                NFCLOG_E("add tech failed, ret = %d", ret);
                goto failed;
            }
        }
    }

    NFCLOG_I("multi-protocol card activation successful");
    notify_tag_detected(s_curr_tag);
    goto cleanup;

failed:
    rf_deactivate(false);
cleanup:
    if (p_activated_params) {
        osi_free(p_activated_params);
    }
    nfa_rw_release_lock();
}
/**
 * @brief 处理单张卡片被激活事件
 */
static void on_tag_activated(tNCI_RF_INTF_ACTIVATED_PARAMS *params) {
    if (nfa_rw_request_lock() != NCI_STATUS_OK) {
        NFCLOG_E("get rw lock failed");
        return;
    }

    if (!s_cback) {
        NFCLOG_E("rw cback is not set");
        goto unlock;
    }

    if (!s_curr_tag) {
        NFCLOG_D("intf activated, but tag info is not set");
        s_curr_tag = rw_utils_create_tag(params);
        if (!s_curr_tag) {
            NFCLOG_E("create tag failed");
            goto unlock;
        }
    }

    notify_tag_detected(s_curr_tag);
unlock:
    nfa_rw_release_lock();
}
/**
 * @brief 处理卡片离场或被去激活事件
 */
static void on_tag_deactivated(bool notify_upper_layer) {
    if (nfa_rw_request_lock() != NCI_STATUS_OK) {
        NFCLOG_E("get rw lock failed");
        return;
    }
    nfa_rw_reset_all_transceive_timeout();

    if (s_curr_tag) {
        tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(s_curr_tag);
        if (p_api && p_api->on_disconnect) {
            p_api->on_disconnect();
        }
        osi_free(s_curr_tag);
    }
    s_curr_tag = NULL;

    nfa_rw_release_lock();

    if (notify_upper_layer && s_cback) {
        s_cback(NCI_RW_EVT_TAG_LOSTED, NULL);
    }
}
/**
 * @brief 读卡模块消息处理函数
 */
static bool rw_task(uint32_t what, uint32_t arg1, uint64_t arg2, void* args) {
    NFCLOG_D("rw task, what = %d, arg1=%d, arg2=%" PRIu64, what, arg1, arg2);
    switch (what) {
        case NCI_TASK_EVT_RW_TAG_DISCOVERED:
            on_tag_discovered((tNCI_RF_DISCOVER_PARAMS*) args, (uint8_t) arg1);
            break;
        case NCI_TASK_EVT_RW_TAG_ACTIVATED:
            on_tag_activated((tNCI_RF_INTF_ACTIVATED_PARAMS*) args);
            break;
        case NCI_TASK_EVT_RW_TAG_LOSTED:
            on_tag_deactivated(true);
            break;
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
        case NCI_TASK_EVT_RW_WATCH_DOG_STOP:
            nfa_rw_watch_dog_stop();
            break;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
        default:
            NFCLOG_E("unknown what = %d", what);
            return false;
    }
    return true;
}
/**
 * @brief 读卡模块消息清理函数
 */
static void rw_task_cleanup(uint32_t what, uint32_t arg1, uint64_t arg2, void* args) {
    if (args) {
        NFCLOG_D("what= %d, arg1 = %d, arg2 = %" PRIu64, what, arg1, arg2);
        osi_free(args);
    }
}
/**
 * @brief 读卡模块初始化函数
 */
static tNCI_STATUS init(const tNCI_MODULE_INIT_CFG *p_cfg) {
    if (osi_mutex_init_with_attr(&s_rw_lock, true) != NFC_STATUS_OK) {
        NFCLOG_E("rw lock init failed");
        goto init_failed;
    }
    if (nci_task_register(rw_task, rw_task_cleanup, NCI_TASK_EVT_RW_GROUP) != NCI_STATUS_OK) {
        NFCLOG_E("register nci task failed");
        goto init_failed;
    }
    s_cback = p_cfg->p_external_cfg ? p_cfg->p_external_cfg->rw_cback : NULL;
    nfa_rw_reset_all_transceive_timeout();
    return NCI_STATUS_OK;

init_failed:
    osi_mutex_deinit(&s_rw_lock);
    nci_task_unregister(NCI_TASK_EVT_RW_GROUP);
    return NCI_STATUS_EXT_FAILED;
}
/**
 * @brief 读卡模块反初始化函数
 */
static tNCI_STATUS deinit(bool is_shutdown) {
    (void) is_shutdown;
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    nfa_rw_watch_dog_stop();
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    on_tag_deactivated(false);
    nci_task_unregister(NCI_TASK_EVT_RW_GROUP);
    osi_mutex_deinit(&s_rw_lock);
    s_cback = NULL;
    return NCI_STATUS_OK;
}
/**
 * @brief 读卡模块dump函数
 */
static void dump(int fd) {
    if (nfa_rw_request_lock() != NCI_STATUS_OK) {
        NFCLOG_E("rw lock failed");
        return;
    }

    if (s_curr_tag) {
        osi_dump(fd, "Tag activated:");
        rw_utils_dump_tag(fd, s_curr_tag);
    } else {
        osi_dump(fd, "No tag activated");
    }

    nfa_rw_release_lock();
}

tNCI_MODULE g_rw_manager = {
    .name = "RW_MANAGER",
    .init = init,
    .deinit = deinit,
    .dump = dump,
};

/**
 * @brief 获取读卡模块内部的锁
 *
 * @note 获取锁后，需要调用rw_unlock()释放锁
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他
 */
tNCI_STATUS nfa_rw_request_lock() {
    return osi_mutex_lock(&s_rw_lock) == NFC_STATUS_OK ? NCI_STATUS_OK : NCI_STATUS_EXT_GET_LOCK_FAILED;
}
/**
 * @brief 释放读卡模块内部的锁
 *
 * @note 需要先调用rw_lock()获取锁
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他
 */
tNCI_STATUS nfa_rw_release_lock() {
    osi_mutex_unlock(&s_rw_lock);
    return NCI_STATUS_OK;
}

/**
 * @brief 获取读卡锁
 *
 * @return 返回读卡锁的指针（不会为NULL）
 */
tMUTEX *rw_get_mutex() {
    return &s_rw_lock;
}

/**
 * @brief 获取当前激活的标签
 *
 * @return 如果当前有激活的标签，则返回该标签指针，否则返回NULL
 */
tNCI_RW_TAG *nfa_rw_get_activated_tag() {
    return s_curr_tag;
}
/**
 * @brief 重新选择当前标签
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他
 */
tNCI_STATUS rw_re_select() {
    GET_RW_LOCK();

    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    tNCI_RW_TAG *p_tag = s_curr_tag;

    if (p_tag) {
        uint8_t index = p_tag->index;
        ret = rf_re_select(p_tag->disc_ids[index], p_tag->protocols[index], p_tag->interfaces[index], WAIT_ACTIVATE_TIMEOUT);
    } else {
        NFCLOG_E("no tag activated");
        ret = NCI_STATUS_EXT_TAG_LOST;
    }

    RELEASE_RW_LOCK();
    return ret;
}

#endif // IS_FEATURE_ON(NCI_FEATURE_RW)
